package com.augrain.microframework.web.advice;

import com.augrain.microframework.core.consts.HttpStats;
import com.augrain.microframework.core.exception.ApplicationException;
import com.augrain.microframework.web.base.ApiContext;
import com.augrain.microframework.web.base.ApiResult;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author biaoy
 * @since 2020/11/25
 */
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
@RestControllerAdvice
public class ApiExceptionAdvice {

    /**
     * 主要应对传入参数犹如导致的@Valid报错
     */
    @ExceptionHandler(BindException.class)
    public Object bindExceptionHandler(BindException ex, HttpServletRequest request) {
        List<FieldError> fieldErrors = ex.getFieldErrors();
        StringBuilder sb = new StringBuilder("");
        fieldErrors.forEach(msg -> sb.append(msg.getField() + msg.getDefaultMessage()).append("\n"));
        ApiContext current = ApiContext.getCurrent();
        String s = sb.toString();
        log.error("参数绑定异常: {}", s);
        return ApiResult.builder().code(HttpStats.HTTP_INTERNAL_ERROR)
                .timestamp(System.currentTimeMillis()).msg(s).api(current == null ? null : current.getApi()).build();
    }

    /**
     * 业务异常统一捕捉，controller层不用再写trycatch 节省代码
     */
    @ExceptionHandler({ApplicationException.class})
    public Object serviceExceptionHandler(ApplicationException ex, HttpServletRequest request) {
        ApiContext current = ApiContext.getCurrent();
        log.error("[业务异常]", ex);
        return ApiResult.builder().code(ex.getCode() == null ? HttpStats.HTTP_INTERNAL_ERROR : ex.getCode())
                .timestamp(System.currentTimeMillis()).msg(ex.getMessage()).data(ex.getData())
                .api(current == null ? null : current.getApi()).build();
    }

    /**
     * 参数异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({IllegalArgumentException.class})
    public Object illegalArgumentExceptionHandler(IllegalArgumentException ex, HttpServletRequest request) {
        ApiContext current = ApiContext.getCurrent();

        log.error("[参数异常]", ex);
        return ApiResult.builder().code(HttpStats.HTTP_INTERNAL_ERROR).timestamp(System.currentTimeMillis())
                .msg(ex.getMessage()).api(current == null ? null : current.getApi()).build();
    }

    @ExceptionHandler({TypeMismatchException.class})
    public Object typeMismatchExceptionHandler(TypeMismatchException ex, HttpServletRequest request) {
        ApiContext current = ApiContext.getCurrent();

        log.error("[类型不匹配]", ex);
        return ApiResult.builder().code(HttpStats.HTTP_INTERNAL_ERROR).timestamp(System.currentTimeMillis())
                .msg(ex.getMessage()).api(current == null ? null : current.getApi()).build();
    }

    // /**
    //  * 参数异常
    //  *
    //  * @param ex
    //  * @return
    //  */
    // @ExceptionHandler({ConstraintViolationException.class})
    // public Object constraintViolationException(ConstraintViolationException ex, HttpServletRequest request) {
    //     ApiContext current = ApiContext.getCurrent();
    //     log.error("[参数异常]", ex);
    //
    //     Set<ConstraintViolation<?>> validate = ex.getConstraintViolations();
    //     String msg = ex.getMessage();
    //     if (!CollectionUtils.isEmpty(validate)) {
    //         msg = validate.stream().map(x -> x.getMessage()).reduce((m1, m2) -> m1 + "；" + m2).orElse("参数输入有误！");
    //     }
    //     ApiResult apiResult = ApiResult.builder().code(ApiErrorCodes.ARGUMENT_INVALIDED)
    //             .timestamp(System.currentTimeMillis()).msg(msg).api(current == null ? null : current.getApi()).build();
    //     return ViewUtils.doResolveView(request, apiResult);
    // }

    /**
     * 参数校验异常
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public Object methodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest request) {
        ApiContext current = ApiContext.getCurrent();
        log.error("[参数异常]", ex);

        BindingResult bindingResult = ex.getBindingResult();
        String msg = bindingResult.getFieldErrors().stream()
                .map(f -> f.getField() + "：" + f.getDefaultMessage())
                .collect(Collectors.joining("；"));

        return ApiResult.builder().code(HttpStats.HTTP_INTERNAL_ERROR)
                .timestamp(System.currentTimeMillis()).msg(msg).api(current == null ? null : current.getApi()).build();
    }

    /**
     * 其它系统异常
     */
    @ExceptionHandler(Throwable.class)
    public Object exceptionHandler(Throwable ex, HttpServletRequest request) {
        ApiContext current = ApiContext.getCurrent();
        log.error("[系统异常]", ex);
        return ApiResult.builder().code(HttpStats.HTTP_INTERNAL_ERROR).timestamp(System.currentTimeMillis())
                .msg(ex.toString()).api(current == null ? null : current.getApi()).build();
    }
}
